/*
 * Copyright (c) 2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "list_test_ng.h"

namespace OHOS::Ace::NG {
namespace {} // namespace

class ListGroupAlgTestNg : public ListTestNg {
public:
};

/**
 * @tc.name: ListItemGroupLayoutAlgorithm001
 * @tc.desc: ListItemGroup  Measure
 * @tc.type: FUNC
 */
HWTEST_F(ListGroupAlgTestNg, ListItemGroupLayoutAlgorithm_NeedMeasureItem001, TestSize.Level1)
{
    /* *
     * @tc.steps: step1. create List/ListItemGroup and Set Space
     */
    int32_t groupNumber = 2;
    int32_t itemNumber = 3;
    ListModelNG model = CreateList();
    model.SetSpace(Dimension(SPACE));
    // head + ListItem + SPACE + ListItem + SPACE + ListItem + Foot
    // FrameNode = 2 * 3
    CreateGroupWithSetting(groupNumber, Axis::VERTICAL, V2::ListItemGroupStyle::NONE, itemNumber);
    CreateDone(frameNode_);

    /* *
     * @tc.steps: step2. get child frame node from index
     */
    auto groupFrameNode = GetChildFrameNode(frameNode_, 0);
    auto groupPattern = groupFrameNode->GetPattern<ListItemGroupPattern>();
    RefPtr<LayoutAlgorithm> layoutAl = groupPattern->CreateLayoutAlgorithm();

    /* *
     * @tc.steps: step3. build a object about ListItemGroupLayoutAlgorithm
     */
    RefPtr<ListItemGroupLayoutAlgorithm> listItemGroupAl = AceType::DynamicCast<ListItemGroupLayoutAlgorithm>(layoutAl);
    RefPtr<LayoutWrapper> layoutWrapper = AceType::DynamicCast<LayoutWrapper>(groupFrameNode);
    LayoutWrapper* wrapper = AceType::RawPtr(layoutWrapper);
    EXPECT_TRUE(listItemGroupAl->forwardLayout_ && listItemGroupAl->headerIndex_ >= 0);

    bool resTypeInit = listItemGroupAl->NeedMeasureItem(wrapper);
    EXPECT_TRUE(resTypeInit);

    listItemGroupAl->headerMainSize_ = 3.1;
    listItemGroupAl->endPos_ = 1.1;

    bool resType = listItemGroupAl->NeedMeasureItem(wrapper);
    EXPECT_FALSE(resType);

    // init data
    listItemGroupAl->headerMainSize_ = 0.0f;
    listItemGroupAl->startPos_ = 0.0f;
    listItemGroupAl->endPos_ = 0.0f;
    listItemGroupAl->referencePos_ = 0.0f;
    listItemGroupAl->totalMainSize_ = 0.0f;
    listItemGroupAl->footerMainSize_ = 0.0f;

    // LessNotEqual check
    listItemGroupAl->totalMainSize_ = 10.1;
    listItemGroupAl->footerMainSize_ = 3.1;
    listItemGroupAl->startPos_ = 8.1;

    resType = listItemGroupAl->NeedMeasureItem(wrapper);
    EXPECT_FALSE(resType);
}

/**
 * @tc.name: ListItemGroupLayoutAlgorithm002
 * @tc.desc: ListItemGroup  Measure
 * @tc.type: FUNC
 */
HWTEST_F(ListGroupAlgTestNg, ListItemGroupLayoutAlgorithm_NeedMeasureItem002, TestSize.Level1)
{
    /* *
     * @tc.steps: step1. create List/ListItemGroup and Set Space
     */
    int32_t groupNumber = 2;
    int32_t itemNumber = 3;
    ListModelNG model = CreateList();
    model.SetSpace(Dimension(SPACE));
    // head + ListItem + SPACE + ListItem + SPACE + ListItem + Foot
    // FrameNode = 2 * 3
    CreateGroupWithSetting(groupNumber, Axis::VERTICAL, V2::ListItemGroupStyle::NONE, itemNumber);
    CreateDone(frameNode_);

    /* *
     * @tc.steps: step2. get child frame node from index
     */
    auto groupFrameNode = GetChildFrameNode(frameNode_, 0);
    auto groupPattern = groupFrameNode->GetPattern<ListItemGroupPattern>();

    RefPtr<LayoutAlgorithm> layoutAl = groupPattern->CreateLayoutAlgorithm();
    RefPtr<LayoutWrapper> layoutWrapper = AceType::DynamicCast<LayoutWrapper>(groupFrameNode);
    LayoutWrapper* wrapper = AceType::RawPtr(layoutWrapper);

    /* *
     * @tc.steps: step3. build a object about ListItemGroupLayoutAlgorithm
     */
    RefPtr<ListItemGroupLayoutAlgorithm> listItemGroupAl = AceType::DynamicCast<ListItemGroupLayoutAlgorithm>(layoutAl);
    EXPECT_TRUE(listItemGroupAl->forwardLayout_ && listItemGroupAl->headerIndex_ >= 0);

    // forwardLayout equ false, GreatNotEqual
    listItemGroupAl->forwardLayout_ = false;
    listItemGroupAl->headerMainSize_ = 3.1;
    listItemGroupAl->referencePos_ = 10.1;
    listItemGroupAl->totalMainSize_ = 10.1;
    listItemGroupAl->endPos_ = 1.1;

    bool resType = listItemGroupAl->NeedMeasureItem(wrapper);
    EXPECT_FALSE(resType);

    // init data
    listItemGroupAl->headerMainSize_ = 0.0f;
    listItemGroupAl->startPos_ = 0.0f;
    listItemGroupAl->endPos_ = 0.0f;
    listItemGroupAl->referencePos_ = 0.0f;
    listItemGroupAl->totalMainSize_ = 0.0f;
    listItemGroupAl->footerMainSize_ = 0.0f;

    // forwardLayout false
    listItemGroupAl->forwardLayout_ = false;
    listItemGroupAl->totalMainSize_ = 10.1;
    listItemGroupAl->footerMainSize_ = 3.1;
    listItemGroupAl->startPos_ = 8.1;
    listItemGroupAl->referencePos_ = 10.1;

    resType = listItemGroupAl->NeedMeasureItem(wrapper);
    EXPECT_FALSE(resType);

    listItemGroupAl->startPos_ = 6.1;
    resType = listItemGroupAl->NeedMeasureItem(wrapper);
    EXPECT_TRUE(resType);
}

/**
 * @tc.name: ListItemGroupLayoutAlgorithm_Layout
 * @tc.desc: set layoutWrapper Property null
 * @tc.type: FUNC
 */
HWTEST_F(ListGroupAlgTestNg, ListItemGroupLayoutAlgorithm_Layout, TestSize.Level1)
{
    /* *
     * @tc.steps: step1. create List/ListItemGroup and Set Space
     */
    int32_t groupNumber = 2;
    int32_t itemNumber = 3;
    ListModelNG model = CreateList();
    model.SetSpace(Dimension(SPACE));
    // head + ListItem + SPACE + ListItem + SPACE + ListItem + Foot
    // FrameNode = 2 * 3
    CreateGroupWithSetting(groupNumber, Axis::VERTICAL, V2::ListItemGroupStyle::NONE, itemNumber);
    CreateDone(frameNode_);

    /* *
     * @tc.steps: step2. get child frame node from index
     */
    auto groupFrameNode = GetChildFrameNode(frameNode_, 0);

    /* *
     * @tc.steps: step3. build a object about layoutWraper
     */
    RefPtr<LayoutWrapper> layoutWrapper = groupFrameNode->CreateLayoutWrapper(true, true);
    RefPtr<LayoutWrapperNode> layoutWrapper_ = AceType::DynamicCast<LayoutWrapperNode>(layoutWrapper);
    // Set LayoutProperty null , CHECK_NULL_VOID eq null
    layoutWrapper_->layoutProperty_ = nullptr;
    const auto &layoutProperty = layoutWrapper->GetLayoutProperty();
    EXPECT_EQ(layoutProperty, nullptr);
    
    /* *
     * @tc.steps: step4. build a object about ListItemGroupLayoutAlgorithm
     */
    auto groupPattern = groupFrameNode->GetPattern<ListItemGroupPattern>();
    RefPtr<LayoutAlgorithm> layoutAl = groupPattern->CreateLayoutAlgorithm();
    RefPtr<ListItemGroupLayoutAlgorithm> listItemGroupAl = AceType::DynamicCast<ListItemGroupLayoutAlgorithm>(layoutAl);
    listItemGroupAl->headerIndex_ = -1;
    listItemGroupAl->Layout(AceType::RawPtr<LayoutWrapper>(layoutWrapper));
}

/**
 * @tc.name: ListLayoutAlgorithmTest001
 * @tc.desc: Test the list layout from right to left
 * @tc.type: FUNC
 * @tc.author:
 */
HWTEST_F(ListGroupAlgTestNg, ListLayoutAlgorithmTest001, TestSize.Level1)
{
    RefPtr<ListPattern> listPattern = AceType::MakeRefPtr<ListPattern>();
    ASSERT_NE(listPattern, nullptr);
    auto frameNode = FrameNode::CreateFrameNode(V2::LIST_ETS_TAG, -1, listPattern);
    ASSERT_NE(frameNode, nullptr);
    RefPtr<GeometryNode> geometryNode = frameNode->GetGeometryNode();
    ASSERT_NE(geometryNode, nullptr);
    /**
     * @tc.steps: step2. call Layout function.
     */
    // set reverse true
    auto listLayoutProperty = frameNode->GetLayoutProperty<ListLayoutProperty>();
    listLayoutProperty->UpdateLayoutDirection(TextDirection::RTL);
    auto layoutWrapper = AceType::MakeRefPtr<LayoutWrapperNode>(nullptr, geometryNode, listLayoutProperty);
    ASSERT_NE(layoutWrapper, nullptr);
    ListLayoutAlgorithm listLayoutAlgorithm;
    LayoutConstraintF layoutConstraint;
    layoutWrapper->layoutProperty_->layoutConstraint_ = layoutConstraint;
    layoutWrapper->layoutProperty_->contentConstraint_ = layoutConstraint;
    struct ListItemInfo listItemInfo1;
    listItemInfo1.startPos = 0.0f;
    listItemInfo1.endPos = 180.0f;
    listLayoutAlgorithm.contentMainSize_ = 720.0f;
    listLayoutAlgorithm.itemPosition_.emplace(std::make_pair(0, listItemInfo1));
    auto wrapper = layoutWrapper->GetOrCreateChildByIndex(listLayoutAlgorithm.itemPosition_.begin()->first);
    auto size = layoutWrapper->GetGeometryNode()->GetMarginFrameSize();
    float crossSize = 300.0f;
    int32_t startIndex = 0;
    listLayoutAlgorithm.LayoutItem(wrapper, 0, listLayoutAlgorithm.itemPosition_.begin()->second,
        startIndex, crossSize);
    float crossOffset = listLayoutAlgorithm.CalculateLaneCrossOffset(crossSize, size.Width());
    auto offset = OffsetF(crossSize - crossOffset - size.Width(), listItemInfo1.startPos);
    EXPECT_EQ(0.f, crossOffset);
    auto layoutDirection = layoutWrapper->GetLayoutProperty()->GetNonAutoLayoutDirection();
    EXPECT_EQ(layoutDirection, TextDirection::RTL);
}

/**
 * @tc.name: ListItemLayoutAlgorithmTest001
 * @tc.desc: Test the listitem layout from right to left
 * @tc.type: FUNC
 * @tc.author:
 */
HWTEST_F(ListGroupAlgTestNg, ListItemLayoutAlgorithmTest001, TestSize.Level1)
{
    RefPtr<ListItemPattern> listItemPattern = AceType::MakeRefPtr<ListItemPattern>(nullptr, V2::ListItemStyle::NONE);
    ASSERT_NE(listItemPattern, nullptr);
    auto frameNode = FrameNode::CreateFrameNode(V2::LIST_ETS_TAG, -1, listItemPattern);
    ASSERT_NE(frameNode, nullptr);
    RefPtr<GeometryNode> geometryNode = frameNode->GetGeometryNode();
    ASSERT_NE(geometryNode, nullptr);
    /**
     * @tc.steps: step2. call Layout function.
     */
    // set reverse true
    auto listItemLayoutProperty = frameNode->GetLayoutProperty<ListItemLayoutProperty>();
    listItemLayoutProperty->UpdateLayoutDirection(TextDirection::RTL);
    auto layoutWrapper = AceType::MakeRefPtr<LayoutWrapperNode>(nullptr, geometryNode, listItemLayoutProperty);
    ASSERT_NE(layoutWrapper, nullptr);
    ListItemLayoutAlgorithm listItemLayoutAlgorithm(0, 0, 0);
    LayoutConstraintF layoutConstraint;
    layoutWrapper->layoutProperty_->layoutConstraint_ = layoutConstraint;
    layoutWrapper->layoutProperty_->contentConstraint_ = layoutConstraint;
    listItemLayoutAlgorithm.Measure(AceType::RawPtr(layoutWrapper));
    listItemLayoutAlgorithm.Layout(AceType::RawPtr(layoutWrapper));
    auto layoutDirection = layoutWrapper->GetLayoutProperty()->GetNonAutoLayoutDirection();
    EXPECT_EQ(layoutDirection, TextDirection::RTL);
}

/**
 * @tc.name: ListItemLayoutAlgorithmTest002
 * @tc.desc: Test the listitem layout from right to left
 * @tc.type: FUNC
 * @tc.author:
 */
HWTEST_F(ListGroupAlgTestNg, ListItemLayoutAlgorithmTest002, TestSize.Level1)
{
    RefPtr<ListItemPattern> listItemPattern = AceType::MakeRefPtr<ListItemPattern>(nullptr, V2::ListItemStyle::NONE);
    ASSERT_NE(listItemPattern, nullptr);
    auto frameNode = FrameNode::CreateFrameNode(V2::LIST_ETS_TAG, -1, listItemPattern);
    ASSERT_NE(frameNode, nullptr);
    RefPtr<GeometryNode> geometryNode = frameNode->GetGeometryNode();
    ASSERT_NE(geometryNode, nullptr);
    /**
     * @tc.steps: step2. call Layout function.
     */
    // set reverse true
    auto listItemLayoutProperty = frameNode->GetLayoutProperty<ListItemLayoutProperty>();
    listItemLayoutProperty->UpdateLayoutDirection(TextDirection::RTL);
    auto layoutWrapper = AceType::MakeRefPtr<LayoutWrapperNode>(nullptr, geometryNode, listItemLayoutProperty);
    ASSERT_NE(layoutWrapper, nullptr);
    ListItemLayoutAlgorithm listItemLayoutAlgorithm(0, 0, 0);
    LayoutConstraintF layoutConstraint;
    layoutWrapper->layoutProperty_->layoutConstraint_ = layoutConstraint;
    layoutWrapper->layoutProperty_->contentConstraint_ = layoutConstraint;
    listItemLayoutAlgorithm.Measure(AceType::RawPtr(layoutWrapper));
    bool value = listItemLayoutAlgorithm.IsRTLAndVertical(AceType::RawPtr(layoutWrapper));
    EXPECT_EQ(value, true);
}

/**
 * @tc.name: ListItemGroupLayout001
 * @tc.desc: Test ListItemGroup rect and itemPosition with V2::ListItemGroupStyle::NONE
 * @tc.type: FUNC
 */
HWTEST_F(ListGroupAlgTestNg, ListItemGroupLayout001, TestSize.Level1)
{
    CreateList();
    CreateGroupWithSetting(1, Axis::VERTICAL, V2::ListItemGroupStyle::NONE);
    CreateDone(frameNode_);
    RefPtr<FrameNode> groupNode = GetChildFrameNode(frameNode_, 0);
    float groupHeight = GROUP_ITEM_NUMBER * (ITEM_HEIGHT + SPACE) - SPACE + GROUP_HEADER_LEN * 2;
    RectF groupRect = GetChildRect(frameNode_, 0);
    RectF headRect = GetChildRect(groupNode, HEADER_INDEX);
    RectF firstItemRect = GetChildRect(groupNode, FOOTER_INDEX + 1);
    RectF secondItemRect = GetChildRect(groupNode, FOOTER_INDEX + 2);
    RectF footRect = GetChildRect(groupNode, FOOTER_INDEX);
    EXPECT_TRUE(IsEqual(groupRect, RectF(0, 0, LIST_WIDTH, groupHeight)));
    EXPECT_TRUE(IsEqual(headRect, RectF(0, 0, LIST_WIDTH, GROUP_HEADER_LEN)));
    EXPECT_TRUE(IsEqual(firstItemRect, RectF(0, GROUP_HEADER_LEN, LIST_WIDTH, ITEM_HEIGHT)));
    EXPECT_TRUE(IsEqual(secondItemRect, RectF(0, GROUP_HEADER_LEN + SPACE + ITEM_HEIGHT, LIST_WIDTH, ITEM_HEIGHT)));
    EXPECT_TRUE(IsEqual(footRect, RectF(0, groupHeight - GROUP_HEADER_LEN, LIST_WIDTH, GROUP_HEADER_LEN)));
}

/**
 * @tc.name: ListItemGroupLayout002
 * @tc.desc: Test ListItemGroup rect and itemPosition with V2::ListItemGroupStyle::CARD
 * @tc.type: FUNC
 */
HWTEST_F(ListGroupAlgTestNg, ListItemGroupLayout002, TestSize.Level1)
{
    CreateList();
    CreateGroupWithSetting(1, Axis::VERTICAL, V2::ListItemGroupStyle::CARD);
    CreateDone(frameNode_);
    RefPtr<FrameNode> groupNode = GetChildFrameNode(frameNode_, 0);
    float groupHeight = GROUP_ITEM_NUMBER * (ITEM_HEIGHT + SPACE) - SPACE + GROUP_HEADER_LEN * 2;
    RectF groupRect = GetChildRect(frameNode_, 0);
    RectF headRect = GetChildRect(groupNode, 0);
    RectF firstItemRect = GetChildRect(groupNode, FOOTER_INDEX + 1);
    RectF secondItemRect = GetChildRect(groupNode, FOOTER_INDEX + 2);
    RectF footRect = GetChildRect(groupNode, 1);
    EXPECT_TRUE(IsEqual(groupRect, RectF(12.f, 0, -60.f, groupHeight)));
    EXPECT_TRUE(IsEqual(headRect, RectF(0, 0, 216.f, GROUP_HEADER_LEN)));
    EXPECT_TRUE(IsEqual(footRect, RectF(0, groupHeight - GROUP_HEADER_LEN, 216.f, GROUP_HEADER_LEN)));
    EXPECT_TRUE(IsEqual(firstItemRect, RectF(0, GROUP_HEADER_LEN, 16.f, ITEM_HEIGHT)));
    EXPECT_TRUE(IsEqual(secondItemRect, RectF(0, GROUP_HEADER_LEN + SPACE + ITEM_HEIGHT, 16.f, ITEM_HEIGHT)));
}

/**
 * @tc.name: Sticky001
 * @tc.desc: List set sticky header and footer
 * @tc.type: FUNC
 */
HWTEST_F(ListGroupAlgTestNg, Sticky001, TestSize.Level1)
{
    /**
     * @tc.steps: step1. V2::StickyStyle::HEADER
     * @tc.expected: head is Sticky
     */
    ListModelNG model = CreateList();
    model.SetSticky(V2::StickyStyle::HEADER);
    CreateGroupWithSetting(GROUP_NUMBER, Axis::VERTICAL, V2::ListItemGroupStyle::NONE);
    CreateDone(frameNode_);
    RefPtr<FrameNode> firstGroupNode = GetChildFrameNode(frameNode_, 0);
    RefPtr<FrameNode> secondGroupNode = GetChildFrameNode(frameNode_, 1);
    EXPECT_EQ(GetChildY(firstGroupNode, HEADER_INDEX), 0.f);
    ScrollTo(ITEM_HEIGHT);
    EXPECT_EQ(GetChildY(firstGroupNode, HEADER_INDEX), ITEM_HEIGHT);

    /**
     * @tc.steps: step2. V2::StickyStyle::FOOTER
     * @tc.expected: foot is Sticky
     */
    ScrollTo(0.f); // reset position
    layoutProperty_->UpdateStickyStyle(V2::StickyStyle::FOOTER);
    frameNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
    FlushLayoutTask(frameNode_);
    float expectOffset = LIST_HEIGHT - GetChildHeight(frameNode_, 0) - GROUP_HEADER_LEN;
    EXPECT_EQ(GetChildY(secondGroupNode, FOOTER_INDEX), GROUP_HEADER_LEN);
    ScrollTo(ITEM_HEIGHT);
    EXPECT_EQ(GetChildY(secondGroupNode, FOOTER_INDEX), expectOffset + ITEM_HEIGHT);

    /**
     * @tc.steps: step3. V2::StickyStyle::BOTH
     * @tc.expected: head/foot is Sticky
     */
    ScrollTo(0.f); // reset position
    layoutProperty_->UpdateStickyStyle(V2::StickyStyle::BOTH);
    frameNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
    FlushLayoutTask(frameNode_);
    EXPECT_EQ(GetChildY(firstGroupNode, HEADER_INDEX), 0.f);
    EXPECT_EQ(GetChildY(secondGroupNode, FOOTER_INDEX), GROUP_HEADER_LEN);
    ScrollTo(ITEM_HEIGHT);
    EXPECT_EQ(GetChildY(firstGroupNode, HEADER_INDEX), ITEM_HEIGHT);
    EXPECT_EQ(GetChildY(secondGroupNode, FOOTER_INDEX), expectOffset + ITEM_HEIGHT);
}

/**
 * @tc.name: Sticky002
 * @tc.desc: List set sticky header and footer in HORIZONTAL and RTL Layout
 * @tc.type: FUNC
 */
HWTEST_F(ListGroupAlgTestNg, Sticky002, TestSize.Level1)
{
    /**
     * @tc.steps: step1. V2::StickyStyle::HEADER
     * @tc.expected: head is Sticky
     */
    AceApplicationInfo::GetInstance().isRightToLeft_ = true;
    ListModelNG model = CreateList();
    model.SetListDirection(Axis::HORIZONTAL);
    model.SetSticky(V2::StickyStyle::HEADER);
    CreateGroupWithSetting(GROUP_NUMBER, Axis::HORIZONTAL, V2::ListItemGroupStyle::NONE);
    CreateDone(frameNode_);
    RefPtr<FrameNode> firstGroupNode = GetChildFrameNode(frameNode_, 0);
    RefPtr<FrameNode> secondGroupNode = GetChildFrameNode(frameNode_, 1);
    EXPECT_EQ(GetChildX(firstGroupNode, HEADER_INDEX), 180.f);
    ScrollTo(ITEM_WIDTH);
    EXPECT_EQ(GetChildX(firstGroupNode, HEADER_INDEX), 120.f);

    /**
     * @tc.steps: step2. V2::StickyStyle::FOOTER
     * @tc.expected: foot is Sticky
     */
    ScrollTo(0.f); // reset position
    layoutProperty_->UpdateStickyStyle(V2::StickyStyle::FOOTER);
    frameNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
    FlushLayoutTask(frameNode_);
    EXPECT_EQ(GetChildX(secondGroupNode, FOOTER_INDEX), 0.f);
    ScrollTo(ITEM_WIDTH);
    EXPECT_EQ(GetChildX(secondGroupNode, FOOTER_INDEX), 70.f);

    /**
     * @tc.steps: step3. V2::StickyStyle::BOTH
     * @tc.expected: head/foot is Sticky
     */
    ScrollTo(0.f); // reset position
    layoutProperty_->UpdateStickyStyle(V2::StickyStyle::BOTH);
    frameNode_->MarkDirtyNode(PROPERTY_UPDATE_MEASURE);
    FlushLayoutTask(frameNode_);
    EXPECT_EQ(GetChildY(firstGroupNode, HEADER_INDEX), 0.f);
    EXPECT_EQ(GetChildY(secondGroupNode, FOOTER_INDEX), 0.f);
    ScrollTo(ITEM_WIDTH);
    EXPECT_EQ(GetChildY(firstGroupNode, HEADER_INDEX), 0.f);
    EXPECT_EQ(GetChildY(secondGroupNode, FOOTER_INDEX), 0.f);
}

/**
 * @tc.name: LanesLayout001
 * @tc.desc: test lanes
 * @tc.type: FUNC
 */
HWTEST_F(ListGroupAlgTestNg, LanesLayout001, TestSize.Level1)
{
    /**
     * @tc.steps: step1. SetLanes 2
     * @tc.expected: has 2 lanes items
     */
    int32_t lanes = 2;
    ListModelNG model = CreateList();
    model.SetLanes(lanes);
    CreateListItemGroups(1);
    CreateDone(frameNode_);
    RefPtr<FrameNode> groupNode = GetChildFrameNode(frameNode_, 0);
    EXPECT_EQ(GetChildHeight(frameNode_, 0), std::ceil(GROUP_ITEM_NUMBER / lanes) * ITEM_HEIGHT);
    EXPECT_LT(GetChildX(groupNode, 0), GetChildX(groupNode, 1));

    /**
     * @tc.steps: step2. maxLaneLength > LIST_WIDTH
     * @tc.expected: has 1 lanes items
     */
    ClearOldNodes();
    model = CreateList();
    model.SetLaneMinLength(Dimension(300.f));
    model.SetLaneMaxLength(Dimension(LIST_WIDTH + 100.f));
    CreateListItemGroups(1);
    CreateDone(frameNode_);
    groupNode = GetChildFrameNode(frameNode_, 0);
    EXPECT_EQ(GetChildWidth(frameNode_, 0), LIST_WIDTH);
    EXPECT_LT(GetChildY(groupNode, 0), GetChildY(groupNode, 1));

    /**
     * @tc.steps: step3. maxLaneLength < LIST_WIDTH
     * @tc.expected: has 1 lanes items
     */
    ClearOldNodes();
    model = CreateList();
    model.SetLaneMinLength(Dimension(300.f));
    model.SetLaneMaxLength(Dimension(400.f));
    CreateListItemGroups(1);
    CreateDone(frameNode_);
    groupNode = GetChildFrameNode(frameNode_, 0);
    EXPECT_EQ(GetChildWidth(frameNode_, 0), LIST_WIDTH);
    EXPECT_LT(GetChildY(groupNode, 0), GetChildY(groupNode, 1));

    /**
     * @tc.steps: step4. SetLanes 2 with header/footer/space ...
     * @tc.expected: has 2 lanes items
     */
    ClearOldNodes();
    model = CreateList();
    model.SetLanes(lanes);
    CreateGroupWithSetting(1, Axis::VERTICAL, V2::ListItemGroupStyle::NONE);
    CreateDone(frameNode_);
    groupNode = GetChildFrameNode(frameNode_, 0);
    EXPECT_LT(GetChildX(groupNode, 2), GetChildX(groupNode, 3));

    /**
     * @tc.steps: step5. set minLaneLength/maxLaneLength with header/footer/space ...
     * @tc.expected: headWidth would be maxLaneLength
     */
    ClearOldNodes();
    model = CreateList();
    model.SetLaneMinLength(Dimension(300.f));
    model.SetLaneMaxLength(Dimension(400.f));
    CreateGroupWithSetting(1, Axis::VERTICAL, V2::ListItemGroupStyle::NONE);
    CreateDone(frameNode_);
    groupNode = GetChildFrameNode(frameNode_, 0);
    EXPECT_EQ(GetChildWidth(groupNode, HEADER_INDEX), LIST_WIDTH);
    EXPECT_LT(GetChildY(groupNode, 2), GetChildY(groupNode, 3));
}

/**
 * @tc.name: ListItemAlign001
 * @tc.desc: test SetListItemAlign
 * @tc.type: FUNC
 */
HWTEST_F(ListGroupAlgTestNg, ListItemAlign001, TestSize.Level1)
{
    /**
     * @tc.steps: step2. V2::ListItemAlign::START
     */
    const float itemWidth = LIST_WIDTH - 100.f;
    ListModelNG model = CreateList();
    model.SetListItemAlign(V2::ListItemAlign::START);
    CreateListItemGroup(V2::ListItemGroupStyle::NONE);
    CreateListItem();
    ViewAbstract::SetWidth(CalcLength(itemWidth));
    CreateDone(frameNode_);
    RefPtr<FrameNode> groupNode = GetChildFrameNode(frameNode_, 0);
    EXPECT_EQ(GetChildX(groupNode, 0), 0);

    /**
     * @tc.steps: step2. V2::ListItemAlign::CENTER
     */
    layoutProperty_->UpdateListItemAlign(V2::ListItemAlign::CENTER);
    FlushLayoutTask(frameNode_);
    EXPECT_EQ(GetChildX(groupNode, 0), (LIST_WIDTH - itemWidth) / 2);

    /**
     * @tc.steps: step3. V2::ListItemAlign::END
     */
    layoutProperty_->UpdateListItemAlign(V2::ListItemAlign::END);
    FlushLayoutTask(frameNode_);
    EXPECT_EQ(GetChildX(groupNode, 0), LIST_WIDTH - itemWidth);
}

/**
 * @tc.name: ListItemAlign002
 * @tc.desc: test SetListItemAlign in RTL Layout
 * @tc.type: FUNC
 */
HWTEST_F(ListGroupAlgTestNg, ListItemAlign002, TestSize.Level1)
{
    /**
     * @tc.steps: step2. V2::ListItemAlign::START
     */
    AceApplicationInfo::GetInstance().isRightToLeft_ = true;
    const float itemWidth = LIST_WIDTH - 100.f;
    ListModelNG model = CreateList();
    model.SetListItemAlign(V2::ListItemAlign::START);
    CreateListItemGroup(V2::ListItemGroupStyle::NONE);
    CreateListItem();
    ViewAbstract::SetWidth(CalcLength(itemWidth));
    CreateDone(frameNode_);
    RefPtr<FrameNode> groupNode = GetChildFrameNode(frameNode_, 0);
    EXPECT_EQ(GetChildX(groupNode, 0), LIST_WIDTH - itemWidth);

    /**
     * @tc.steps: step2. V2::ListItemAlign::CENTER
     */
    layoutProperty_->UpdateListItemAlign(V2::ListItemAlign::CENTER);
    FlushLayoutTask(frameNode_);
    EXPECT_EQ(GetChildX(groupNode, 0), (LIST_WIDTH - itemWidth) / 2);

    /**
     * @tc.steps: step3. V2::ListItemAlign::END
     */
    layoutProperty_->UpdateListItemAlign(V2::ListItemAlign::END);
    FlushLayoutTask(frameNode_);
    EXPECT_EQ(GetChildX(groupNode, 0), 0);
}

/**
 * @tc.name: ListGroupRepeatCacheCount001
 * @tc.desc: ListItemGroup cacheCount
 * @tc.type: FUNC
 */
HWTEST_F(ListGroupAlgTestNg, ListGroupRepeatCacheCount001, TestSize.Level1)
{
    ListModelNG model = CreateList();
    ListItemGroupModelNG groupModel = CreateListItemGroup();
    auto header = GetRowOrColBuilder(FILL_LENGTH, Dimension(GROUP_HEADER_LEN));
    groupModel.SetHeader(std::move(header));
    CreateRepeatVirtualScrollNode(10, [this](int32_t idx) {
        CreateListItem();
        ViewStackProcessor::GetInstance()->Pop();
        ViewStackProcessor::GetInstance()->StopGetAccessRecording();
    });
    CreateDone(frameNode_);

    /**
     * @tc.steps: step1. Check Repeat frameCount
     */
    auto groupNode = AceType::DynamicCast<FrameNode>(frameNode_->GetChildAtIndex(0));
    auto repeat = AceType::DynamicCast<RepeatVirtualScrollNode>(groupNode->GetChildAtIndex(1));
    EXPECT_NE(repeat, nullptr);
    int32_t frameCount = repeat->FrameCount();
    EXPECT_EQ(frameCount, 10);

    /**
     * @tc.steps: step2. Flush Idle Task
     * @tc.expected: ListItem 4 is cached
     */
    auto listPattern = frameNode_->GetPattern<ListPattern>();
    FlushIdleTask(listPattern);
    int32_t childrenCount = repeat->GetChildren().size();
    EXPECT_EQ(childrenCount, 5);
    auto cachedItem = groupNode->GetChildByIndex(4 + 1)->GetHostNode();
    EXPECT_EQ(cachedItem->IsActive(), false);

    /**
     * @tc.steps: step3. Flush Idle Task
     * @tc.expected: ListItem 1 and 7 is cached, ListItem 2,3,4,5,6 is active.
     */
    UpdateCurrentOffset(-300, SCROLL_FROM_JUMP);
    FlushIdleTask(listPattern);
    childrenCount = repeat->GetChildren().size();
    EXPECT_EQ(childrenCount, 7);
    cachedItem = groupNode->GetChildByIndex(1 + 1)->GetHostNode();
    EXPECT_EQ(cachedItem->IsActive(), false);
    cachedItem = groupNode->GetChildByIndex(7 + 1)->GetHostNode();
    EXPECT_EQ(cachedItem->IsActive(), false);
}

/**
 * @tc.name: ListGroupRepeatCacheCount002
 * @tc.desc: ListItemGroup lanes cacheCount
 * @tc.type: FUNC
 */
HWTEST_F(ListGroupAlgTestNg, ListGroupRepeatCacheCount002, TestSize.Level1)
{
    ListModelNG model = CreateList();
    model.SetLanes(2);
    ListItemGroupModelNG groupModel = CreateListItemGroup();
    auto header = GetRowOrColBuilder(FILL_LENGTH, Dimension(GROUP_HEADER_LEN));
    groupModel.SetHeader(std::move(header));
    CreateRepeatVirtualScrollNode(20, [this](int32_t idx) {
        CreateListItem();
        ViewStackProcessor::GetInstance()->Pop();
        ViewStackProcessor::GetInstance()->StopGetAccessRecording();
    });
    CreateDone(frameNode_);

    /**
     * @tc.steps: step1. Check Repeat frameCount
     */
    auto groupNode = AceType::DynamicCast<FrameNode>(frameNode_->GetChildAtIndex(0));
    auto repeat = AceType::DynamicCast<RepeatVirtualScrollNode>(groupNode->GetChildAtIndex(1));
    EXPECT_NE(repeat, nullptr);
    int32_t frameCount = repeat->FrameCount();
    EXPECT_EQ(frameCount, 20);

    /**
     * @tc.steps: step2. Flush Idle Task
     * @tc.expected: ListItem 10,11 is cached
     */
    auto listPattern = frameNode_->GetPattern<ListPattern>();
    FlushIdleTask(listPattern);
    int32_t childrenCount = repeat->GetChildren().size();
    EXPECT_EQ(childrenCount, 10);
    auto item8 = groupNode->GetChildByIndex(8 + 1)->GetHostNode();
    EXPECT_EQ(item8->IsActive(), false);
    auto item9 = groupNode->GetChildByIndex(9 + 1)->GetHostNode();
    EXPECT_EQ(item9->IsActive(), false);

    /**
     * @tc.steps: step3. Flush Idle Task
     * @tc.expected: ListItem 2,3,14,15 is cached, ListItem 4-13 active.
     */
    UpdateCurrentOffset(-300, SCROLL_FROM_JUMP);
    FlushIdleTask(listPattern);
    childrenCount = repeat->GetChildren().size();
    EXPECT_EQ(childrenCount, 14);
    auto item2 = groupNode->GetChildByIndex(2 + 1)->GetHostNode();
    EXPECT_EQ(item2->IsActive(), false);
    auto item3 = groupNode->GetChildByIndex(3 + 1)->GetHostNode();
    EXPECT_EQ(item3->IsActive(), false);
    auto item14 = groupNode->GetChildByIndex(14 + 1)->GetHostNode();
    EXPECT_EQ(item14->IsActive(), false);
    auto item15 = groupNode->GetChildByIndex(15 + 1)->GetHostNode();
    EXPECT_EQ(item15->IsActive(), false);
}

/**
 * @tc.name: ListGroupRepeatCacheCount003
 * @tc.desc: ListItemGroup lanes cacheCount
 * @tc.type: FUNC
 */
HWTEST_F(ListGroupAlgTestNg, ListGroupRepeatCacheCount003, TestSize.Level1)
{
    ListModelNG model = CreateList();
    model.SetCachedCount(2);
    model.SetSticky(V2::StickyStyle::BOTH);
    CreateRepeatVirtualScrollNode(3, [this](int32_t idx) {
        ListItemGroupModelNG groupModel = CreateListItemGroup();
        auto header = GetRowOrColBuilder(FILL_LENGTH, Dimension(GROUP_HEADER_LEN));
        groupModel.SetHeader(std::move(header));
        CreateRepeatVirtualScrollNode(5, [this](int32_t idx) {
            CreateListItem();
            ViewStackProcessor::GetInstance()->Pop();
            ViewStackProcessor::GetInstance()->StopGetAccessRecording();
        });
    });
    CreateDone(frameNode_);

    /**
     * @tc.steps: step1. Check Repeat frameCount
     */
    auto repeat = AceType::DynamicCast<RepeatVirtualScrollNode>(frameNode_->GetChildAtIndex(0));
    EXPECT_EQ(repeat->FrameCount(), 3);

    /**
     * @tc.steps: step2. Flush Idle Task
     * @tc.expected: Group0 ListItem 4 is cached, Group1 ListItem1 is cached
     */
    auto listPattern = frameNode_->GetPattern<ListPattern>();
    FlushIdleTask(listPattern);
    // check group0
    auto groupNode0 = AceType::DynamicCast<FrameNode>(frameNode_->GetChildByIndex(0));
    auto repeat0 = AceType::DynamicCast<RepeatVirtualScrollNode>(groupNode0->GetChildAtIndex(1));
    int32_t childrenCount = repeat0->GetChildren().size();
    EXPECT_EQ(childrenCount, 5);
    auto g0Item4 = groupNode0->GetChildByIndex(4 + 1)->GetHostNode();
    EXPECT_EQ(g0Item4->IsActive(), false);
    // check group1
    auto groupNode1 = AceType::DynamicCast<FrameNode>(frameNode_->GetChildByIndex(1));
    auto repeat1 = AceType::DynamicCast<RepeatVirtualScrollNode>(groupNode1->GetChildAtIndex(1));
    childrenCount = repeat1->GetChildren().size();
    EXPECT_EQ(childrenCount, 1);
    auto g1Item0 = groupNode1->GetChildByIndex(0 + 1)->GetHostNode();
    EXPECT_EQ(g1Item0->IsActive(), false);

    /**
     * @tc.steps: step3. Flush Idle Task
     * @tc.expected: group0 item4 cached, group1 item0 cached, group2 item0-1 cached
     */
    UpdateCurrentOffset(-725);
    FlushIdleTask(listPattern);
    // check group 0
    childrenCount = repeat0->GetChildren().size();
    EXPECT_EQ(childrenCount, 1);
    g0Item4 = groupNode0->GetChildByIndex(4 + 1)->GetHostNode();
    EXPECT_EQ(g0Item4->IsActive(), false);
    // check group 0
    childrenCount = repeat1->GetChildren().size();
    EXPECT_EQ(childrenCount, 5);
    g1Item0 = groupNode1->GetChildByIndex(0 + 1)->GetHostNode();
    EXPECT_EQ(g1Item0->IsActive(), false);
    // check group 2
    auto groupNode2 = AceType::DynamicCast<FrameNode>(frameNode_->GetChildByIndex(2));
    auto repeat2 = AceType::DynamicCast<RepeatVirtualScrollNode>(groupNode2->GetChildAtIndex(1));
    childrenCount = repeat2->GetChildren().size();
    EXPECT_EQ(childrenCount, 2);
    auto g2item0 = groupNode2->GetChildByIndex(0 + 1)->GetHostNode();
    EXPECT_EQ(g2item0->IsActive(), false);
    auto g2item1 = groupNode2->GetChildByIndex(1 + 1)->GetHostNode();
    EXPECT_EQ(g2item1->IsActive(), false);
}
} // namespace OHOS::Ace::NG
